package utils

import (
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"github.com/shopspring/decimal"
	"math/rand"
	"os"
	"reflect"
	"strings"
	"time"
	"yundian/internel/pkg/dingo/global"
)

func ResolveTime(seconds int) (hour, minute, second int) {
	var day = seconds / (24 * 3600)
	hour = (seconds - day*3600*24) / 3600
	minute = (seconds - day*24*3600 - hour*3600) / 60
	second = seconds - day*24*3600 - hour*3600 - minute*60
	return
}

func GetHourDiffer(startTime, endTime string) int64 {
	var hour int64
	t1, err := time.ParseInLocation("2006-01-02 15:04:05", startTime, time.Local)
	t2, err := time.ParseInLocation("2006-01-02 15:04:05", endTime, time.Local)
	if err == nil && t1.Before(t2) {
		diff := t2.Unix() - t1.Unix() //
		hour = diff / 3600
		return hour
	} else {
		return hour
	}
}

func GetMinuteDiffer(startTime, endTime string) int64 {
	var minute int64
	t1, err := time.ParseInLocation("2006-01-02 15:04:05", startTime, time.Local)
	t2, err := time.ParseInLocation("2006-01-02 15:04:05", endTime, time.Local)
	if err == nil && t1.Before(t2) {
		diff := t2.Unix() - t1.Unix() //
		minute = diff / 60
		return minute
	} else {
		return minute
	}
}

// 判断文件是否存在
func PathExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

// 字符串连接
func Join(strs ...string) string {
	return strings.Join(strs, "")
}

// md5加密
func Str2Md5(str string) string {
	h := md5.New()
	h.Write([]byte(str))
	return hex.EncodeToString(h.Sum(nil))
}

// 判断string是否在[]string中
func Contains(strs []string, e string) bool {
	for _, s := range strs {
		if s == e {
			return true
		}
	}
	return false
}

// 判断int是否在[]int中
func ContainsInt(strs []int, e int) bool {
	for _, s := range strs {
		if s == e {
			return true
		}
	}
	return false
}

func UTCTransLocal(utcTime string) string {
	t, _ := time.Parse("2006-01-02T15:04:05.000+08:00", utcTime)
	return t.Local().Format("2006-01-02 15:04:05")
}

// 随机生成指定位数的数字的组合
func GetRandomInt(l int) string {
	str := "0123456789"
	bytes := []byte(str)
	result := make([]byte, 0)
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < l; i++ {
		result = append(result, bytes[r.Intn(len(bytes))])
	}
	return string(result)
}

// 随机生成指定位数的大写字母和小写字母的组合
func GetRandomString(l int) string {
	str := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	bytes := []byte(str)
	result := make([]byte, 0)
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < l; i++ {
		result = append(result, bytes[r.Intn(len(bytes))])
	}
	return string(result)
}

// 随机生成指定位数的大小写字母和数字的组合
func GetRandomStringAndInt(l int) string {
	str := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	bytes := []byte(str)
	result := make([]byte, 0)
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < l; i++ {
		result = append(result, bytes[r.Intn(len(bytes))])
	}
	return string(result)
}

//分转元
func Fen2Yuan(price int64) string {
	d := decimal.New(1, 2) //分除以100得到元
	result := decimal.NewFromInt(price).DivRound(d, 2).String()
	//fmt.Printf("输入值为：%d,      分转元后，精度为二的结果为：%s\n", price, result)
	return result
}

//元转分,乘以100后，保留整数部分
func Yuan2Fen(price float64) int64 {
	d := decimal.New(1, 2) //分转元乘以100
	//d1 := decimal.New(1,0)//乘完之后，保留2为小数，需要这么一个中间参数
	//df := decimal.NewFromFloat(price).Mul(d).DivRound(d1,2).String()
	df := decimal.NewFromFloat(price).Mul(d).IntPart()

	//如下是满足，当乘以100后，仍然有小数位，取四舍五入法后，再取整数部分
	//dff := decimal.NewFromFloat(price).Mul(d).DivRound(d1,0).IntPart()
	//fmt.Printf("输入值为：%f, 简单的元转分后，取整数部分：%d\n", price, df)
	//fmt.Printf("输入值为：%f, 元转分后，若还有小数，需做四舍五入后，再取整数：%d\n", price, dff)
	return df
}

// EncryptPassword 密码加密码
func EncryptPassword(passwd string) string {
	//h := md5.New()
	//h.Write([]byte(global.Cfg.Server.PwdSecret))
	//return hex.EncodeToString(h.Sum([]byte(passwd)))
	s := []byte(passwd)
	key := []byte(global.Cfg.Server.PwdSecret)
	m := hmac.New(sha256.New, key)
	m.Write(s)
	signature := hex.EncodeToString(m.Sum(nil))
	return signature
}

// Struct2Map 结构体转为Map[string]interface{}
func Struct2Map(in interface{}, tagName string) (map[string]interface{}, error) {
	out := make(map[string]interface{})

	v := reflect.ValueOf(in)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}

	if v.Kind() != reflect.Struct { // 非结构体返回错误提示
		return nil, fmt.Errorf("ToMap only accepts struct or struct pointer; got %T", v)
	}

	t := v.Type()
	// 遍历结构体字段
	// 指定tagName值为map中key;字段值为map中value
	for i := 0; i < v.NumField(); i++ {
		fi := t.Field(i)
		if tagValue := fi.Tag.Get(tagName); tagValue != "" {
			out[tagValue] = v.Field(i).Interface()
		}
	}
	return out, nil
}

// ToMap2 将结构体嵌套结构体转为单层map
func ToMap2(in interface{}, tag string) (map[string]interface{}, error) {

	// 当前函数只接收struct类型
	v := reflect.ValueOf(in)
	if v.Kind() == reflect.Ptr { // 结构体指针
		v = v.Elem()
	}
	if v.Kind() != reflect.Struct {
		return nil, fmt.Errorf("ToMap only accepts struct or struct pointer; got %T", v)
	}

	out := make(map[string]interface{})
	queue := make([]interface{}, 0, 1)
	queue = append(queue, in)

	for len(queue) > 0 {
		v := reflect.ValueOf(queue[0])
		if v.Kind() == reflect.Ptr { // 结构体指针
			v = v.Elem()
		}
		queue = queue[1:]
		t := v.Type()
		for i := 0; i < v.NumField(); i++ {
			vi := v.Field(i)
			if vi.Kind() == reflect.Ptr { // 内嵌指针
				vi = vi.Elem()
				if vi.Kind() == reflect.Struct { // 结构体
					queue = append(queue, vi.Interface())
				} else {
					ti := t.Field(i)
					if tagValue := ti.Tag.Get(tag); tagValue != "" {
						// 存入map
						out[tagValue] = vi.Interface()
					}
				}
				break
			}
			if vi.Kind() == reflect.Struct { // 内嵌结构体
				queue = append(queue, vi.Interface())
				break
			}
			// 一般字段
			ti := t.Field(i)
			if tagValue := ti.Tag.Get(tag); tagValue != "" {
				// 存入map
				out[tagValue] = vi.Interface()
			}
		}
	}
	return out, nil
}

// Map2Struct Map转Struct
func Map2Struct(m map[string]interface{}, u interface{}) {
	v := reflect.ValueOf(u)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
		if v.Kind() != reflect.Struct {
			panic("must struct")
		}
		findFromMap := func(key string) interface{} {
			for k, v := range m {
				if k == key {
					return v
				}
			}
			return nil
		}
		for i := 0; i < v.NumField(); i++ {
			val := findFromMap(v.Type().Field(i).Name)
			if val != nil && reflect.ValueOf(val).Kind() == v.Field(i).Kind() {
				v.Field(i).Set(reflect.ValueOf(val))
			}
		}
	} else {
		panic("must ptr")
	}
}

// ToStruct 可根据结构体字段或tag标签来转换
func ToStruct(m map[string]interface{}, u interface{}) {
	v := reflect.ValueOf(u)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
		if v.Kind() != reflect.Struct {
			panic("must struct")
		}
		findFromMap := func(key string, nameTag string) interface{} {
			for k, v := range m {
				if k == key || k == nameTag {
					return v
				}
			}
			return nil
		}
		for i := 0; i < v.NumField(); i++ {
			val := findFromMap(v.Type().Field(i).Name, v.Type().Field(i).Tag.Get("name"))
			if val != nil && reflect.ValueOf(val).Kind() == v.Field(i).Kind() {
				v.Field(i).Set(reflect.ValueOf(val))
			}
		}
	} else {
		panic("must ptr")
	}
}

// 通过map主键唯一的特性过滤重复元素
func RemoveRepByMap(slc []int) []int {
	var result []int
	tempMap := map[int]byte{} // 存放不重复主键
	for _, e := range slc {
		l := len(tempMap)
		tempMap[e] = 0
		if len(tempMap) != l { // 加入map后，map长度变化，则元素不重复
			result = append(result, e)
		}
	}
	return result
}
